package com.nowcoder.community.service;

import com.nowcoder.community.entity.User;
import com.nowcoder.community.util.CommunityConstant;
import com.nowcoder.community.util.RedisKeyUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.SessionCallback;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * <p>Title: FollowService</p>
 * <p>author 12427</p>
 *
 * @version ver1.0
 * @date 2022/8/20 20:41
 */
@Service
public class FollowService implements CommunityConstant {

    @Autowired
    private RedisTemplate redisTemplate ;

    @Autowired
    private UserService userService ;

    public  void follow(int userId,  int entityType , int entityId) {
        redisTemplate.execute(new SessionCallback() {
            @Override
            public Object execute(RedisOperations operations) throws DataAccessException {
                String followeeKey  = RedisKeyUtil.getFolloweeKey(userId , entityType) ; // 根据人和实体类型，找到这个人都关注了某个实体的哪些实体
                String followerKey = RedisKeyUtil.getFollowerKey(entityType , entityId) ;   // 根据实体类型和实体ID找到这个实体被哪些用户关注
                operations.multi();

                operations.opsForZSet().add(followeeKey , entityId , System.currentTimeMillis()) ;
                operations.opsForZSet().add(followerKey , userId , System.currentTimeMillis()) ;


                return operations.exec() ;
            }
        }) ;
    }
    public  void unfollow(int userId,  int entityType , int entityId) {
        redisTemplate.execute(new SessionCallback() {
            @Override
            public Object execute(RedisOperations operations) throws DataAccessException {
                String followeeKey  = RedisKeyUtil.getFolloweeKey(userId , entityType) ; // 根据人和实体类型，找到这个人都关注了某个实体的哪些实体
            String followerKey = RedisKeyUtil.getFollowerKey(entityType , entityId) ;   // 根据实体类型和实体ID找到这个实体被哪些用户关注
                operations.multi();

                operations.opsForZSet().remove(followeeKey , entityId , System.currentTimeMillis()) ;
                operations.opsForZSet().remove(followerKey , userId , System.currentTimeMillis()) ;


                return operations.exec() ;
        }
        }) ;
    }


    /**
     * 查询某人关注实体的数量
     * @param userId
     * @param entityType
     * @return
     */
    public long findFolloweeCount(int userId , int entityType){
        String followeeKey = RedisKeyUtil.getFolloweeKey(userId , entityType) ;
        return redisTemplate.opsForZSet().zCard(followeeKey) ;
    }

    /**
     * 查询某实体的粉丝数量
     * @param entityType
     * @param entityId
     * @return
     */
    public long findFollowerCount(int entityType ,int entityId){
        String followerKey = RedisKeyUtil.getFollowerKey(entityType,entityId) ;
        return redisTemplate.opsForZSet().zCard(followerKey) ;
    }


    /**
     * 查询当前用户userId是否已经关注该实体entityType:entityId
     * @param userId
     * @param entityType
     * @param entityId
     * @return
     */
    public boolean hasFollowed(int userId , int entityType ,int entityId) {
        String followeeKey = RedisKeyUtil.getFolloweeKey(userId , entityType ) ;
        // 判断原理 : 根据userId 和 entityType 锁定这个人关注了关注了entityType的哪些实体
        // 然后查找这些实体里面的entityId的score是多少
        // 能查到，就是关注了，不能查到就是没有
        return redisTemplate.opsForZSet().score(followeeKey , entityId ) != null ;
    }

    /**
     * 查询某用户关注的人
     * @return
     */
    public List<Map<String,Object>> findFollowees( int userId , int offset , int limit){
        String followeeKey = RedisKeyUtil.getFolloweeKey(userId, ENTITY_TYPE_USER);
        Set<Integer> targetIds = redisTemplate.opsForZSet().reverseRange(followeeKey, offset, offset + limit - 1);

        if(targetIds == null) {
            return null ;
        }

        List<Map<String,Object>> list = new ArrayList<>() ;
        for(Integer targetId : targetIds) {
            Map<String , Object> map = new HashMap<>() ;
            User user = userService.findUserById(targetId);
            map.put("user" , user) ;
            Double score = redisTemplate.opsForZSet().score(followeeKey, targetId);
            // 具体时间和毫秒数的转化
            map.put("followTime"  , new Date(score.longValue())) ;
            list.add(map) ;
        }
        return list ;
    }

    /**
     * 查询某用户的粉丝
     * @return
     */
    public List<Map<String,Object>> findFollowers( int userId , int offset , int limit){
        String followerKey = RedisKeyUtil.getFollowerKey( ENTITY_TYPE_USER , userId); // 注意参数顺序
        Set<Integer> targetIds = redisTemplate.opsForZSet().reverseRange(followerKey, offset, offset + limit - 1);

        if(targetIds == null) {
            return null ;
        }

        List<Map<String,Object>> list = new ArrayList<>() ;
        for(Integer targetId : targetIds) {
            Map<String , Object> map = new HashMap<>() ;
            User user = userService.findUserById(targetId);
            map.put("user" , user) ;
            Double score = redisTemplate.opsForZSet().score(followerKey, targetId);
            // 具体时间和毫秒数的转化
            map.put("followTime"  , new Date(score.longValue())) ;
            list.add(map) ;
        }
        return list ;
    }



}
